﻿// -------------------------------------------------------------------------
//    @FileName         :    GameApi.cpp
//    @Author           :    gaoyi
//    @Date             :    24-8-1
//    @Email            :    445267987@qq.com
//    @Module           :    GameApi
//
// -------------------------------------------------------------------------

#include "GameApi.h"

#include <NFComm/NFCore/NFSocketLibFunction.h>
#include <NFComm/NFPluginModule/NFIMessageModule.h>
#include <NFLogicCommon/CustomPacketParse.h>

#include "AuthAction.h"
#include "LoginAction.h"

GameApi::GameApi(NFIPluginManager* p): NFIDynamicModule(p)
{
	NFSecurity::InitClient();
	m_iSocketFd = -1;
	m_eState    = EN_STATE_NONE;
	m_iSendSeq  = 0;
	m_iRecvSize = 0;
	m_szSendBuffer.AssureSpace(MAX_PACKET_LEN);
	m_szRecvBuf.AssureSpace(MAX_PACKET_LEN);

	m_iActorID = 0;
	m_iProf    = 0;

	m_ullLoginRoleID     = 0;
	m_iLastHeartBeatTime = 0;

	m_ullGuildId        = 0;
	m_iGuildListPageIdx = 0;
	m_ullApplyGuildId   = 0;
}

GameApi::~GameApi()
{
}

int GameApi::Init(int uid)
{
	m_iUid = uid;
	snprintf(m_szOpenID, MAX_OPEN_ID_LEN, "hunter_%d", uid);

	m_encrypt_type  = proto_client2access::E_NO_ENCRYPT;
	m_compress_type = proto_client2access::E_NO_COMPRESS;
	return 0;
}

int GameApi::Login(int uid, int iActorID, const std::string& pszIp, int iPort)
{
	m_iUid     = uid;
	m_iActorID = iActorID;
	snprintf(m_szOpenID, MAX_OPEN_ID_LEN, "hunter_%d", m_iUid);

	//1) connect svr
	int iRetCode = LoginSvr(pszIp, iPort);
	CHECK_EXPR(iRetCode == 0, iRetCode, "LoginSvr failed!");

	//2)get role list
	NFLogDebug(NF_LOG_DEFAULT, 0, "--login req begin--!");

	LoginReqAction oLoginReq(this);
	iRetCode = oLoginReq.Exec();
	CHECK_EXPR(iRetCode == 0, -1, "login req failed!");
	return 0;
}

int GameApi::LoginSvr(const std::string& pszIp, int iPort)
{
	int iRetCode = ConnectSvr(pszIp, iPort);
	CHECK_EXPR(iRetCode == 0, -1, "connect svr failed!");

	AuthSynAction oAuthSyn(this, GetSendSeq());
	iRetCode = oAuthSyn.Exec();
	CHECK_EXPR(iRetCode == 0, -1, "auth syn failed!");

	AuthAckAction oAuthAck(this, GetSendSeq());
	iRetCode = oAuthAck.Exec();
	CHECK_EXPR(iRetCode == 0, -1, "auth ack failed!");
	return 0;
}

int GameApi::ConnectSvr(const std::string& pszIp, int iPort)
{
	std::string url = NF_FORMAT("tcp://{}:{}", pszIp, iPort);
	m_iSocketFd     = NFSocketLibFunction::Connect(false, pszIp, iPort);
	CHECK_EXPR(m_iSocketFd != NF_INVALID_SOCKET, -1, "connect svr failed, ip:{} port:{} error:{}", pszIp, iPort, strerror(errno));
	NFSocketLibFunction::SocketSetSendSize(m_iSocketFd, 10240);
	NFSocketLibFunction::SocketSetRecvSize(m_iSocketFd, 10240);
	m_eState = EN_STATE_CONNECTED;
	return 0;
}

int GameApi::DisconnectSvr()
{
	return 0;
}

int GameApi::Recv(char* pszBuff, int iMaxLen)
{
	CHECK_NULL(0, pszBuff);

	int iRetCode = recv(m_iSocketFd, pszBuff, iMaxLen, 0);
	if (iRetCode < 0)
	{
		if (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK)
		{
			return 0;
		}
		else
		{
			NFLogError(NF_LOG_DEFAULT, 0, "recv msg failed! error:{}", strerror(errno));
			return -1;
		}
	}
	else if (iRetCode == 0)
	{
		NFLogError(NF_LOG_DEFAULT, 0, "RoleID:{} session disconnect:{}", m_ullLoginRoleID, NFGetSecondTime());
		return -1;
	}

	return iRetCode;
}

int GameApi::Send(proto_client2access::Proto_C2ACmd iCmd, const std::string& strSerial, uint32_t seq)
{
	proto_client2access::C2AMsgHead       oMsgHead;
	const ::google::protobuf::Descriptor* descriptor = oMsgHead.GetDescriptor();
	CHECK_NULL(0, descriptor);
	const ::google::protobuf::FieldDescriptor* field_descriptor = descriptor->FindFieldByName("magic");
	CHECK_NULL(0, field_descriptor);

	oMsgHead.set_msg_seq(seq);
	oMsgHead.set_magic(field_descriptor->default_value_int32());
	oMsgHead.set_cmd(iCmd);
	oMsgHead.set_transferdata_len(strSerial.size());

	::std::string strSerialHead;
	oMsgHead.SerializePartialToString(&strSerialHead);

	int32_t iTotalLen = MSG_HEAD_LEN + strSerialHead.size() + strSerial.size();
	m_szSendBuffer.Clear();
	if ((int32_t)m_szSendBuffer.WritableSize() < iTotalLen)
	{
		NFLogError(NF_LOG_DEFAULT, 0, "net server send data failed, buffer size:{}, iTotalLen:{} head:6 C2AMsgHead:{} unLen:{}", m_szSendBuffer.WritableSize(), iTotalLen, strSerialHead.size(), strSerial.size());
		return -1;
	}

	char*     pPackBuf = m_szSendBuffer.WriteAddr();
	uint16_t* iLens    = (uint16_t *)pPackBuf;
	uint32_t* lens32   = (uint32_t *)pPackBuf;
	lens32[0]          = htonl(iTotalLen);
	iLens[2]           = htons((uint16_t)strSerialHead.size());
	m_szSendBuffer.Produce(MSG_HEAD_LEN);
	m_szSendBuffer.PushData(strSerialHead.data(), strSerialHead.size());
	m_szSendBuffer.PushData(strSerial.data(), strSerial.size());

	NFSocketLibFunction::SocketSend(m_iSocketFd, m_szSendBuffer.ReadAddr(), m_szSendBuffer.ReadableSize());

	return 0;
}

int GameApi::Send(proto_client2access::Proto_C2ACmd iCmd, const google::protobuf::Message& xData, uint32_t seq)
{
	std::string strSerial;
	xData.SerializePartialToString(&strSerial);
	return Send(iCmd, strSerial, seq);
}

int GameApi::Send(uint32_t nMsgId, proto_ff::Proto_CSReq& oCSReq, uint32_t seq)
{
	oCSReq.set_timestamp(NF_ADJUST_TIMENOW_MS());

	m_szSendBuffer.Clear();
	CSC2SPkgHead appHead;
	std::string  str;
	bool         ok = oCSReq.SerializePartialToString(&str);
	CHECK_EXPR(ok, -3, "SerializePartialToString failed");

	appHead.m_wCmd     = htons(nMsgId);
	appHead.m_wDataLen = htons(str.size());
	appHead.m_wSeq     = htons(seq);

	int iRet = 0;
	if (m_szSendBuffer.WritableSize() > str.size() + sizeof(appHead))
	{
		m_szSendBuffer.PushData(&appHead, sizeof(appHead));
		m_szSendBuffer.PushData(str.data(), str.size());

		string strSeriar;
		strSeriar.assign(m_szSendBuffer.ReadAddr(), m_szSendBuffer.ReadableSize());
		std::string output;
		bool        bOK = package_compress_encrypt(m_compress_type, m_encrypt_type, strSeriar, output);
		if (bOK)
		{
			iRet = Send(proto_client2access::E_C2A_TRANSFERDATA, output, seq);
		}
		else
		{
			NFLogError(NF_LOG_DEFAULT, 0, "package_compress_encrypt failed!, msgid:{}", nMsgId);
			return -1;
		}
	}
	else
	{
		NFLogError(NF_LOG_DEFAULT, 0, "packet buff is not enough, , msgid:{}", nMsgId);
		return -1;
	}

	return iRet;
}

int GameApi::HandleCSPacket(int iCmd, proto_ff::Proto_CSRsp& oCSRsp)
{
	switch (iCmd)
	{
		case proto_ff::E_CS_ROLE_NTF:
		{
			const proto_ff::Proto_CSRoleNtf&  oRoleNtf = oCSRsp.role_ntf();
			const proto_ff::GuildRoleSnsData& oSnsData = oRoleNtf.guild_data();
			m_ullGuildId                               = oSnsData.guild_base_info().guild_id();

			break;
		}
		default:
			break;
	}

	return 0;
}
